package com.cjj.refresh;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;

import java.security.SecureRandom;

import java.util.ArrayList;
import java.util.List;

/**
 * RainView
 *
 * @author cjj
 * @since 2015/8/31
 */
public class RainView extends Component implements Component.DrawTask {
    private static final int INVALIDATE_CODE = 10;

    private List<Rain> mRains;

    private List<Rain> mCopyRains;

    private SecureRandom mRandom = new SecureRandom();

    private volatile boolean mIsStop = false;

    private volatile Thread mThread;

    private float mStartY = -20;
    private float mSpeedY = 25;
    private float mRainWidth = 3;
    private float mRainLength = 15;

    double mGradient = 8 * Math.PI / 180;

    private final MyHandler eventHandler = new MyHandler(EventRunner.getMainEventRunner());

    public RainView(Context context) {
        this(context, null);
    }

    public RainView(Context context, AttrSet attrs) {
        super(context, attrs);
        mRains = new ArrayList<>();
        mCopyRains = new ArrayList<>();
        addDrawTask(this);
    }

    /**
     * startRain
     */
    public void startRain() {
        mIsStop = false;
        mThread = new Thread(() -> {
            while (!mIsStop) {
                Paint paint = new Paint();
                for (int i1 = 0; i1 < mRandom.nextInt() * 50 + 100; i1++) {
                    Rain rain = new Rain();
                    rain.setwPoint(mRainWidth);
                    rain.setSpeedY(mSpeedY);
                    paint.reset();
                    paint.setColor(new Color(0Xffffff));
                    paint.setAlpha(90);
                    paint.setStrokeWidth((float) new SecureRandom().nextDouble() * (mRainWidth - 1) + 1);
                    rain.setPaint(paint);
                    int xValue = mRandom.nextInt(getEstimatedWidth() + 1);
                    rain.setX(xValue);
                    rain.setyPoint(mStartY);
                    float speedX = (float) (Math.tan(mGradient) * mSpeedY);
                    rain.setSpeedX(speedX);
                    mRains.add(rain);
                }
                eventHandler.sendEvent(INVALIDATE_CODE);
                try {
                    Thread.sleep(30);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        mThread.start();
    }

    private class MyHandler extends EventHandler {
        MyHandler(EventRunner runner) throws IllegalArgumentException {
            super(runner);
        }

        @Override
        protected void processEvent(InnerEvent event) {
            super.processEvent(event);
            if (event.eventId == INVALIDATE_CODE) {
                invalidate();
            }
        }
    }

    /**
     * stopRain
     */
    public void stopRain() {
        mIsStop = true;
        mThread = null;
        mRains.clear();
        invalidate();
    }

    private Rain rainNext(Rain bubble, float length) {
        Rain next = new Rain();
        next.setX((float) (bubble.getX() + length * Math.sin(mGradient)));
        next.setyPoint((float) (bubble.getyPoint() + length * Math.cos(mGradient)));
        return next;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (mRains == null || mRains.size() <= 0) {
            return;
        }
        mCopyRains.clear();
        mCopyRains.addAll(mRains);
        for (Rain rain : mCopyRains) {
            if (rain == null) {
                return;
            }
            if (rain.getX() <= 0) {
                mRains.remove(rain);
            } else if (rain.getX() >= getWidth()) {
                mRains.remove(rain);
            } else if (rain.getyPoint() > (double) mStartY + getHeight()) {
                mRains.remove(rain);
            }

            rain.setX((float) (rain.getX() + (double) rain.getSpeedX()));
            rain.setyPoint((float) (rain.getyPoint() + (double) rain.getSpeedY()));
            Rain nextRain = rainNext(rain, mRainLength);
            canvas.drawLine(rain.getX(), rain.getyPoint(), nextRain.getX(), nextRain.getyPoint(), rain.getPaint());
        }
    }

    @Override
    public void addDrawTask(DrawTask task) {
        super.addDrawTask(task);
        onDraw(this, mCanvasForTaskOverContent);
    }
}